home *** CD-ROM | disk | FTP | other *** search
/ Ian & Stuart's Australian Mac 1993 September / September 93.iso / Archives / Fun, Tricks & Hacks / Silent Alarm, not! / SonicAlarmMisc.c < prev    next >
Text File  |  1992-06-15  |  18KB  |  699 lines

  1. #ifdef THINK_C
  2.     #include <MacHeaders>
  3. #else
  4.     #pragma load "MPWHeaders"
  5. #endif
  6.  
  7. #include <StdDef.h>
  8. #include <Palettes.h>
  9.  
  10. #ifndef __SONICALARM__
  11. #include "SonicAlarm.h"
  12. #endif
  13.  
  14. #ifndef __SONICALARMMISC__
  15. #include "SonicAlarmMisc.h"
  16. #endif
  17.  
  18. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  19. // globals used for sound routines
  20.  
  21. // gSndInputRef is the sound input device's reference number 
  22. long                gSndInputRef;
  23.  
  24. // gSndChanPtr is a sound channel for playing sounds, duh 
  25. SndChannelPtr        gSndChanPtr;
  26.  
  27. // snd resource handle of our sound
  28. Handle                gSndHandle;
  29.  
  30. // handle state of last snd resource
  31. char                gOldState;
  32.  
  33. // handle used for averaging volume levels
  34. short                    **gLevelsArray;
  35.  
  36. // this is the index of the next volume level to record
  37. short                    gLevelIndex;
  38.  
  39. // percentage represented as a Fixed point number
  40. Fixed                    gSensitivity;
  41.  
  42.  
  43. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  44. // private prototypes 
  45.  
  46.  
  47. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  48. // determine if the machine has a sound input driver running
  49. Boolean HasSoundInput(void)
  50. {
  51.     long        gestaltResult;
  52.     OSErr        err;
  53.     
  54.     err = Gestalt(gestaltSoundAttr, &gestaltResult);
  55.     FailIf(err != noErr, GestaltErr);
  56.  
  57.     return ( (gestaltResult >> gestaltHasSoundInputDevice) & 1 );
  58.  
  59. GestaltErr:
  60.     return (false);
  61. }
  62.  
  63. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  64. OSErr InitSndTools(void)
  65. {
  66.     OSErr        err;
  67.     short        meterOn;
  68.     
  69.     gSndInputRef = 0;
  70.     gSndChanPtr = nil;
  71.     err = SndNewChannel(&gSndChanPtr, sampledSynth, 0, nil);
  72.     FailIf(err != noErr, ChanErr);
  73.  
  74.     err = SPBOpenDevice(nil, siWritePermission, &gSndInputRef);
  75.     FailIf(err != noErr, SndInErr);
  76.  
  77.     meterOn = 1;
  78.     err = SPBSetDeviceInfo(gSndInputRef, siLevelMeterOnOff, (Ptr)&meterOn);
  79.     FailIf(err != noErr, SndInErr);
  80.  
  81.     return (noErr);
  82.  
  83. SndInErr:
  84.     SndDisposeChannel(gSndChanPtr, true);
  85. ChanErr:
  86.     return (err);
  87. }
  88.  
  89. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  90. void CloseSndTools(void)
  91. {
  92.     CloseSndChan();
  93.     CloseSndDevice();
  94.     if (gSndHandle != nil)
  95.         DisposHandle(gSndHandle);
  96. }
  97.  
  98. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  99. void CloseSndDevice(void)
  100. {
  101.     OSErr        err;
  102.  
  103.     if (gSndInputRef != 0) {
  104.         err = SPBCloseDevice(gSndInputRef);
  105.         FailIf(err != noErr, SndErr);
  106.     }
  107.  
  108. SndErr:
  109.     return;
  110. }
  111.  
  112. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  113. // find the sound header inside of the given snd handle
  114.  
  115. OSErr GetBufferOffset(Handle sndHandle, long *offset)
  116. {
  117.     short        howManyCmds;
  118.     Ptr           cruisePtr;
  119.     OSErr        result;
  120.  
  121.     FailIf(sndHandle == nil, BadHandle);
  122.     FailIf(*sndHandle == nil, BadHandle);
  123.  
  124.     result = noErr;
  125.     *offset = 0;
  126.  
  127.     // set the pointer past the first two words of the snd
  128.     // this is correct for both format 1 and 2 resources
  129.     cruisePtr = *sndHandle + offsetof(SndListResource, modifierPart);
  130.  
  131.     // if it's a format 1, then point past the modifier parts
  132.     if ( ((SndListPtr)*sndHandle)->format == firstSoundFormat )
  133.         cruisePtr += sizeof(ModRef) * ((SndListPtr)*sndHandle)->numModifiers;
  134.  
  135.     // now pointing at number of cmds
  136.     howManyCmds = *((short *)cruisePtr);
  137.     cruisePtr += sizeof(howManyCmds);
  138.  
  139.     // cruisePtr is now at the first sound command
  140.     // cruise all commands and find a soundCmd or bufferCmd
  141.     do {
  142.         switch (((SndCmdPtr)cruisePtr)->cmd) {
  143.  
  144.             case (soundCmd | dataOffsetFlag):
  145.             case (bufferCmd | dataOffsetFlag):
  146.                 *offset = ((SndCmdPtr)cruisePtr)->param2;
  147.                 howManyCmds = 0;                // done, get out of loop
  148.                 break;
  149.  
  150.             default:                            // catch any other type of cmd
  151.                 cruisePtr += sizeof(SndCommand);
  152.                 howManyCmds -= 1;
  153.                 break;
  154.         }
  155.     } while (howManyCmds >= 1);                    // done with all the commands
  156.  
  157.     FailWithAction(*offset == 0, result = badFormat, Failure);
  158.     return(result);
  159.  
  160. BadHandle:
  161.     result = nilHandleErr;
  162. Failure:
  163.     return(result);
  164. }
  165. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  166. Boolean IsPlayingSound(void)
  167. {
  168.     SCStatus        theStatus;
  169.     OSErr            err;
  170.         
  171.     err = SndChannelStatus(gSndChanPtr, sizeof(theStatus), &theStatus);
  172.     if (err == noErr)
  173.         return (theStatus.scChannelBusy);
  174.     else
  175.         return (false);
  176. }
  177.  
  178. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  179. OSErr PlaySound(short resID)
  180. {
  181.     SndCommand    theCmd;
  182.     long        offset;
  183.     OSErr        err;
  184.     
  185.     StopPlaying();
  186.     
  187.     gSndHandle = GetResource('snd ', resID);
  188.     FailIf(gSndHandle == nil, NoHandle)
  189.     gOldState = HGetState(gSndHandle);
  190.     HNoPurge(gSndHandle);
  191.     HLock(gSndHandle);
  192.         
  193.     err = GetBufferOffset(gSndHandle, &offset);
  194.     FailIf(err != noErr, NoHandle)
  195.  
  196.     theCmd.cmd = bufferCmd;
  197.     theCmd.param1 = 0;
  198.     theCmd.param2 = (long) *gSndHandle + offset;
  199.     err = SndDoCommand(gSndChanPtr, &theCmd, true);
  200.     FailIf(err != noErr, CmdErr)
  201.     return (noErr);
  202.  
  203. CmdErr:
  204.     HSetState(gSndHandle, gOldState);
  205. NoHandle:
  206.     return (err);
  207. }
  208.  
  209. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  210. void StopPlaying(void)
  211. {
  212.     OSErr            err;
  213.     SndCommand        theCmd;
  214.     
  215.     theCmd.cmd = flushCmd;
  216.     err = SndDoImmediate(gSndChanPtr, &theCmd);
  217.     FailIf(err != noErr, CmdErr)
  218.     
  219.     theCmd.cmd = quietCmd;
  220.     err = SndDoImmediate(gSndChanPtr, &theCmd);
  221.     FailIf(err != noErr, CmdErr)
  222.  
  223. CmdErr:
  224.     HSetState(gSndHandle, gOldState);
  225.     return;
  226. }
  227.  
  228. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  229. void CloseSndChan(void)
  230. {
  231.     OSErr            err;
  232.  
  233.     err = SndDisposeChannel(gSndChanPtr, true);
  234.     FailIf(err != noErr, ChanErr);
  235.     gSndChanPtr = nil;
  236.  
  237. ChanErr:
  238.     return;
  239. }
  240.  
  241. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  242. short GetCurLevel(void)
  243. {
  244.     OSErr            err;
  245.     short            meterData[2];
  246.     
  247.     err = SPBGetDeviceInfo(gSndInputRef, siLevelMeterOnOff, (Ptr) meterData);
  248.     FailIf(err != noErr, SndErr);
  249.  
  250.     if (meterData[0])                        // level metering on?
  251.         return (meterData[1]);
  252.  
  253. SndErr:
  254.     return (0);
  255. }
  256.  
  257. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  258. void DrawCountDown(WindowPtr window, Point location, long *lastTickCount, short *secondsCountDown)
  259. {
  260.     Str255            delayStr;
  261.     long            curTicks;
  262.  
  263.     // are we active and did more than a second pass yet?
  264.     curTicks = TickCount();
  265.     if (*lastTickCount + kOneSecondTicks < curTicks) {
  266.         *lastTickCount = curTicks;
  267.         SetPort(window);
  268.  
  269.         TextFont(kActivatingFontID);
  270.         TextSize(kActivatingFontSize);
  271.     
  272.         // erase the previous number
  273.         ForeColor(whiteColor);
  274.         NumToString(*secondsCountDown + 1, delayStr);
  275.         MoveTo(location.h - StringWidth(delayStr), location.v);
  276.         DrawString(delayStr);
  277.         
  278.         // draw the next number
  279.         ForeColor(redColor);
  280.         NumToString(*secondsCountDown, delayStr);
  281.         MoveTo(location.h - StringWidth(delayStr), location.v);
  282.         DrawString(delayStr);
  283.     
  284.         // restore the foreground color
  285.         ForeColor(blackColor);
  286.  
  287.         (*secondsCountDown)--;
  288.     }
  289. }
  290.  
  291. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  292. // draw dots on the screen for each char in password
  293.  
  294. void DrawPassword(Rect drawArea, short length)
  295. {
  296.     FontInfo    info;
  297.     short        i;
  298.     
  299.     TextFont(systemFont);
  300.     TextSize(kSystemFontSize);
  301.     GetFontInfo(&info);
  302.     MoveTo(drawArea.left + kEditTextInset,
  303.             drawArea.bottom - info.descent - kEditTextInset);
  304.     InsetRect(&drawArea, kEditTextInset, kEditTextInset);
  305.     EraseRect(&drawArea);
  306.     for (i = length - 1; i >= 0; --i)
  307.         DrawChar((short)charBullet);
  308. }
  309.  
  310. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  311. Boolean IsVolumeTooLoud(void)
  312. {
  313.     Fixed        percentage;
  314.  
  315.     if (IsPlayingSound())
  316.         return (false);
  317.     else {
  318.         percentage = (GetCurLevel() << 16) / GetAverageLevel();
  319.         if (percentage < ((kMimimumSensivity << 16) / 100))
  320.             percentage = ((kMimimumSensivity << 16) / 100);
  321.     }
  322.     return (percentage > gSensitivity);
  323. }
  324.  
  325. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  326. short GetAverageLevel(void)
  327. {
  328.     short        i;
  329.     long        result;
  330.     short        *nextLevel;
  331.  
  332.     result = 0;
  333.     nextLevel = *gLevelsArray;
  334.     
  335.     for (i = kNumberOfLevels - 1; i >=0; --i)
  336.         result += *nextLevel++;
  337.  
  338.     return (result >> kNumLevelsShift);
  339. }
  340.  
  341. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  342. void UpdateAverageLevel(void)
  343. {
  344.     if ( !IsPlayingSound() ) {
  345.  
  346.         if ( gLevelIndex > (kNumberOfLevels - 1) )
  347.             gLevelIndex = 0;
  348.             
  349.         (*gLevelsArray)[gLevelIndex++] = GetCurLevel();
  350.     }
  351. }
  352.  
  353. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  354. // pass in a percentage number (i.e. 10% is the number 10)
  355.  
  356. void SetSensitivity(short percentage)
  357. {
  358.     gSensitivity = (percentage << 16) / 100;
  359.     gSensitivity += kFixed100Percent;
  360. }
  361.  
  362. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  363. // returns a percentage number (i.e. 10% is the number 10)
  364.  
  365. short GetSensitivity(void)
  366. {
  367.     Fixed        result;
  368.  
  369.     result = (gSensitivity - kFixed100Percent) * 100;
  370.     
  371.     // if greator that xx.5 then add 1
  372.     if ((result & 0x0000FFFF) > 0x00008000)
  373.         result += 0x00010000;
  374.         
  375.     return (result >> 16);
  376. }
  377.  
  378. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  379. // InitGraf is always implemented (trap 0xA86E). If the trap table is big
  380. // enough, trap 0xAA6E will always point to either Unimplemented or some other
  381. // trap, but will never be the same as InitGraf. Thus, you can check the size
  382. // of the trap table by asking if the address of trap 0xA86E is the same as 0xAA6E.
  383.  
  384. short NumToolboxTraps(void)
  385. {
  386.     if ( GetToolboxTrapAddress(_InitGraf) == GetToolboxTrapAddress(0xAA6E) )
  387.         return (0x0200);
  388.     else
  389.         return (0x0400);
  390. }
  391.  
  392. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  393. // Check to see if a given trap is implemented.  GetTrapAddress may fuck up and
  394. // wrap around into the trap table if you give it a toolbox trap that is out of
  395. // range, so check for this first.
  396.  
  397. Boolean TrapExists(short theTrap)
  398. {
  399.     long            trapAddress;
  400.  
  401.     if ( IsBitsAreClear(theTrap, kOSTrapBit) )
  402.         trapAddress = GetOSTrapAddress(theTrap);
  403.     else {
  404.         ClearBits(kATrapBits, theTrap);                    // get the trap number
  405.         if ( theTrap < NumToolboxTraps() )                // can this tool trap exist?
  406.             trapAddress = GetToolTrapAddress(theTrap);
  407.         else
  408.             return (false);
  409.     }
  410.  
  411.     return ( GetToolboxTrapAddress(_Unimplemented) != trapAddress );
  412. }
  413.  
  414. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  415. Boolean FailLowMemory(long memRequested)
  416. {
  417.     long        total;
  418.     long        contig;
  419.     
  420.     PurgeSpace(&total, &contig);
  421.     return (total < (memRequested + kMinHeap));
  422. }
  423.  
  424. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  425. void AlertUser(short errNum, short errStrIndex, Boolean fatal)
  426. {
  427.     short        itemHit;
  428.     Str255        msg1;
  429.     Str255        msg2;
  430.  
  431.     if (errNum != userCanceledErr) {                        // ignore cancels
  432.         SetCursor(&qd.arrow);
  433.         if (errNum)
  434.             NumToString(errNum, msg1);
  435.         else
  436.             msg1[0] = 0;                                    // empty string
  437.         GetIndString(msg2, kErrStrings, errStrIndex);
  438.         ParamText(msg1, msg2, "\p", "\p");
  439.         itemHit = Alert(rUserAlert, nil);
  440.         if (fatal)
  441.             ExitToShell();
  442.     }
  443. }
  444.  
  445. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  446. OSErr CreateLevelArray(void)
  447. {
  448.     OSErr        result;
  449.  
  450.     result = noErr;
  451.     gLevelIndex = 0;
  452.  
  453.     FailWithAction(FailLowMemory(kNumberOfLevels * sizeof(short)), result = MemError(), NoArray);
  454.         
  455.     gLevelsArray = (short **)NewHandleClear(kNumberOfLevels * sizeof(short));
  456.     FailWithAction(gLevelsArray == nil, result = MemError(), NoArray);
  457.  
  458.  
  459. NoArray:
  460.     return (result);
  461. }
  462.  
  463. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  464. // limit the Pascal string to the max, and return the new length
  465. // there's a Pascal length byte, so subtract one too (three four)
  466.  
  467. unsigned char LimitStringLength(StringPtr pString, unsigned char max)
  468. {
  469.     short        length;
  470.     
  471.     length = Length(pString);
  472.     if (length > (max - 1))
  473.         length = 0;
  474.     length++;
  475.     
  476.     *pString = length;
  477.     return (length);
  478. }
  479.  
  480. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  481. // Check to see if a window belongs to a desk accessory.
  482.  
  483. Boolean IsDAWindow(WindowPtr window)
  484. {
  485.     if (window == nil)
  486.         return false;
  487.     else                                // DA windows have negative windowKinds
  488.         return ((WindowPeek) window)->windowKind < 0;
  489. }
  490.  
  491. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  492. // Given the button control handle, this will cause the button to look as
  493. // if it has been clicked in.  This is nice to do for the user if they type
  494. // return or enter to select the default item.
  495.  
  496. void SelectButton(ControlHandle button)
  497. {
  498.     long        finalTicks;
  499.  
  500.     HiliteControl(button, kSelect);
  501.     Delay(kVisualDelay, &finalTicks);
  502.     HiliteControl(button, kDeselect);
  503. }
  504.  
  505. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  506. void* GetMyWindow(long windowSize, short windID)
  507. {
  508.     Ptr            window;
  509.     long        response;
  510.     OSErr        err;
  511.     Boolean        hasColor;
  512.     
  513.     err = Gestalt(gestaltQuickdrawFeatures, &response);
  514.     hasColor = (err == noErr) && (response & (1 << gestaltHasColor));
  515.  
  516.     window = NewPtrClear(windowSize);
  517.     FailIf(window == nil, NoPtr)
  518.     
  519.     if (hasColor)
  520.         window = (Ptr)GetNewCWindow(windID, window, (WindowPtr)-1);
  521.     else
  522.         window = (Ptr)GetNewWindow(windID, window, (WindowPtr)-1);
  523.     
  524.     FailIf(window == nil, NoWindow)
  525.     
  526.     SetPort((WindowPtr)window);
  527.     SetWRefCon((WindowPtr)window, windID);
  528.     return (window);
  529.  
  530. NoWindow:
  531.     DisposePtr(window);
  532. NoPtr:
  533.     return (nil);
  534. }
  535.  
  536. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  537. // make sure there's a window pointer and get it's type from the refCon
  538.  
  539. long GetMyWindowType(WindowPtr window)
  540. {
  541.     long        result;
  542.  
  543.     result = 0;
  544.     if (window != nil)
  545.         result = GetWRefCon(window);
  546.     return (result);
  547. }
  548.  
  549. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  550. Boolean    IsWindowModal(WindowPtr window)
  551. {
  552.     Boolean        result;
  553.     short        variant;
  554.     
  555.     result = false;
  556.     
  557.     if (window != nil) {
  558.         variant = GetWVariant(window);
  559.         result = (variant == dBoxProc) || (variant == movableDBoxProc);
  560.     }
  561.     return (result);
  562. }
  563.  
  564. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  565. void* FindMyWindow(short windRefCon)
  566. {
  567.     WindowPtr        window;
  568.     
  569.     window = FrontWindow();
  570.     while (window != nil) {
  571.         if (GetWRefCon(window) != windRefCon)
  572.             window = (WindowPtr)((WindowPeek)window)->nextWindow;
  573.         else
  574.             break;
  575.     }
  576.     return (window);
  577. }
  578.  
  579. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  580. ControlHandle GetMyControl(short cntlRefCon, WindowPtr window)
  581. {
  582.     ControlHandle        cntlHandle;
  583.  
  584.     cntlHandle = GetNewControl(cntlRefCon, window);
  585.     if (cntlHandle != nil)
  586.         SetCRefCon(cntlHandle, cntlRefCon);
  587.     return (cntlHandle);
  588. }
  589.  
  590. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  591. ControlHandle FindMyControl(WindowPtr window, short cntlRefCon)
  592. {
  593.     ControlHandle        cntlHandle;
  594.     
  595.     cntlHandle = ((WindowPeek)(window))->controlList;
  596.     while (cntlHandle != nil) {
  597.         if (GetCRefCon(cntlHandle) != cntlRefCon)
  598.             cntlHandle = (**cntlHandle).nextControl;
  599.         else
  600.             break;
  601.     }
  602.     return (cntlHandle);
  603. }
  604.  
  605. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  606. void ActivateControls(WindowPtr window, Boolean becomingActive)
  607. {
  608.     ControlHandle        cntlHandle;
  609.     
  610.     cntlHandle = ((WindowPeek)(window))->controlList;
  611.     while (cntlHandle != nil) {
  612.         HiliteControl(cntlHandle, becomingActive ? kCntlActivate : kCntlDeactivate);
  613.         cntlHandle = (**cntlHandle).nextControl;
  614.     }
  615. }
  616.  
  617. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  618. // this is a DeviceLoopDrawingProcPtr, which is an easy way to find the target GDevice
  619.  
  620. pascal void OutlineControl(short depth, short deviceFlags, GDHandle targetDevice, ControlHandle button)
  621. {
  622. #pragma unused (depth, deviceFlags)
  623.  
  624.     WindowPtr    oldPort;
  625.     Rect        theRect;
  626.     PenState    curPen;
  627.     RGBColor    backColor;
  628.     RGBColor    foreColor;
  629.     RGBColor    grayColor;
  630.     short        buttonOval;
  631.     Boolean        isColor;
  632.  
  633.     if (button != nil) {
  634.         GetPort(&oldPort);
  635.         SetPort((*button)->contrlOwner);
  636.         GetPenState(&curPen);
  637.         PenNormal();
  638.         theRect = (*button)->contrlRect;
  639.         InsetRect(&theRect, kButtonFrameInset, kButtonFrameInset);
  640.         buttonOval = (theRect.bottom - theRect.top) / 2 + 2;
  641.  
  642.         // check for a color window
  643.         if (((CGrafPtr)(*button)->contrlOwner)->portVersion & kIsColorPort)
  644.             isColor = true;
  645.         else
  646.             isColor = false;
  647.         
  648.         if (isColor) {
  649.             GetBackColor(&backColor);
  650.             GetForeColor(&foreColor);
  651.             grayColor = foreColor;
  652.         }
  653.         
  654.         if ((**button).contrlHilite == kCntlDeactivate) {
  655.             
  656.             // find a nice gray for color windows, otherwise use a gray pattern
  657.             if ((isColor) && GetGray(targetDevice, &backColor, &grayColor))
  658.                 RGBForeColor(&grayColor);
  659.             else
  660.                 PenPat((ConstPatternParam)&qd.gray);
  661.         }
  662.         
  663.         PenSize(kButtonFrameSize, kButtonFrameSize);
  664.         FrameRoundRect(&theRect, buttonOval, buttonOval);
  665.         if (isColor)
  666.             RGBForeColor(&foreColor);
  667.         SetPenState(&curPen);
  668.         SetPort(oldPort);
  669.     }
  670. }
  671.  
  672. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  673. // Find the greatest overlap device for the given global rectangle.
  674.  
  675. GDHandle GetRectDevice(Rect globalRect)
  676. {
  677.     long        area, maxArea;
  678.     GDHandle    device, deviceToReturn;
  679.     Rect        intersection;
  680.  
  681.     deviceToReturn = GetMainDevice();            /* Use as default choice. */
  682.     maxArea = 0;
  683.  
  684.     for (device = GetDeviceList(); device; device = GetNextDevice(device)) {
  685.         if (TestDeviceAttribute(device, screenDevice)
  686.           && TestDeviceAttribute(device, screenActive)
  687.           && SectRect(&globalRect, &((*device)->gdRect), &intersection)) {
  688.             area = ((long)(intersection.right - intersection.left)) *
  689.                    ((long)(intersection.bottom - intersection.top));
  690.             if (area > maxArea) {
  691.                 deviceToReturn = device;
  692.                 maxArea = area;
  693.             }
  694.         }
  695.     }
  696.     return(deviceToReturn);
  697. }
  698.  
  699.